﻿// Decompiled with JetBrains decompiler
// Type: Netick.Unity.NetworkObjectPool
// Assembly: Netick.Unity, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E128C7FD-39ED-4452-86AC-6EC748457030
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.xml

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

#nullable disable
namespace Netick.Unity;

internal class NetworkObjectPool
{
  public readonly NetworkSandbox Sandbox;
  public readonly GameObject Prefab;
  public readonly int Id;
  public bool HideUnspawned = true;
  public bool UsePool;
  public int PreloadAmount;
  private readonly Stack<GameObject> Free = new Stack<GameObject>(64 /*0x40*/);
  private readonly List<GameObject> All = new List<GameObject>(64 /*0x40*/);

  public NetworkObjectPool(
    NetworkSandbox sandbox,
    GameObject prefab,
    int preloadAmount,
    bool hideUnspawned,
    int id)
  {
    this.Sandbox = sandbox;
    this.Prefab = prefab;
    this.HideUnspawned = hideUnspawned;
    this.Id = id;
    this.PreloadAmount = preloadAmount;
    this.Free = new Stack<GameObject>(64 /*0x40*/);
    this.All = new List<GameObject>(64 /*0x40*/);
  }

  public void Preload(int count)
  {
    for (int index = 0; index < count; ++index)
      this.Free.Push(this.Create(Vector3.zero, Quaternion.identity, false));
  }

  public void DestroyEverything()
  {
    this.UsePool = false;
    for (int index = 0; index < this.All.Count; ++index)
    {
      if ((Object) this.All[index] != (Object) null)
        Object.Destroy((Object) this.All[index]);
    }
    this.Free.Clear();
    this.All.Clear();
  }

  public void Decommission()
  {
    this.CleanupAllFree();
    this.UsePool = false;
  }

  public void CleanupAllFree()
  {
    this.UsePool = false;
    while (this.Free.Count > 0)
    {
      GameObject gameObject = this.Free.Pop();
      if ((Object) gameObject != (Object) null)
      {
        this.All.Remove(gameObject);
        if (gameObject.GetComponent<NetworkObject>().Entity != null)
        {
          if (this.Sandbox.IsServer)
            this.Sandbox.ServerDestroyObject(gameObject, true);
          else
            this.Sandbox.ClientDestroyObject(gameObject.GetComponent<NetworkObject>());
        }
      }
    }
    this.UsePool = true;
  }

  public void Reload()
  {
    if (!this.UsePool)
      return;
    this.CleanupAllFree();
    this.Preload(this.PreloadAmount);
  }

  public GameObject Get(Vector3 pos, Quaternion rot, bool hasTransformData)
  {
    if (!this.UsePool)
    {
      GameObject gameObject = this.GetNew(pos, rot, hasTransformData);
      gameObject.hideFlags = HideFlags.None;
      gameObject.SetActive(true);
      return gameObject;
    }
    GameObject gameObject1;
    if (this.Free.Count > 0)
    {
      gameObject1 = this.Free.Pop();
      gameObject1.transform.position = pos;
      gameObject1.transform.rotation = rot;
    }
    else
      gameObject1 = this.Create(pos, rot, hasTransformData);
    gameObject1.hideFlags = HideFlags.None;
    gameObject1.SetActive(true);
    return gameObject1;
  }

  private GameObject GetNew(Vector3 pos, Quaternion rot, bool hasTransformData)
  {
    GameObject gameObject = this.Create(pos, rot, hasTransformData);
    gameObject.hideFlags = this.HideUnspawned ? HideFlags.HideInHierarchy : HideFlags.None;
    return gameObject;
  }

  private GameObject Create(Vector3 pos, Quaternion rot, bool hasTransformData)
  {
    GameObject gameObject = hasTransformData ? Object.Instantiate<GameObject>(this.Prefab, pos, rot) : Object.Instantiate<GameObject>(this.Prefab);
    this.ConfigurePrefab(gameObject.GetComponent<NetworkObject>(), this.Id);
    this.Init(gameObject);
    if (this.UsePool)
      this.All.Add(gameObject);
    if (this.Sandbox.Scene != gameObject.gameObject.scene)
      SceneManager.MoveGameObjectToScene(gameObject.gameObject, this.Sandbox.Scene);
    gameObject.hideFlags = this.HideUnspawned ? HideFlags.HideInHierarchy : HideFlags.None;
    gameObject.SetActive(false);
    return gameObject;
  }

  private void Init(GameObject obj)
  {
    NetworkObject component;
    if (obj.TryGetComponent<NetworkObject>(out component) && (component.gameObject.activeInHierarchy || this.Sandbox.Config.IncludeInactiveObjects))
    {
      component.InitLocally(this.Sandbox, (NetworkScene) null);
      this.Sandbox.Engine.CreateAndLinkEntityLocal((INetickEntity) component);
      component.IsPrefabInstance = true;
    }
    for (int index = 0; index < obj.transform.childCount; ++index)
      this.Init(obj.transform.GetChild(index).gameObject);
  }

  private void ConfigurePrefab(NetworkObject obj, int id)
  {
    obj.PrefabId = id;
    obj._SceneId = -1;
    obj.PrefabRoot = (NetworkObject) null;
    obj.PrefabIndex = -1;
    List<NetworkObject> rootChildren = new List<NetworkObject>(2);
    foreach (Component component in obj.transform)
      this.ConfigurePrefabChild(component.gameObject, id, rootChildren, obj, obj.IsPersistent);
    obj.Children = rootChildren.ToArray();
  }

  private void ConfigurePrefabChild(
    GameObject obj,
    int prefabId,
    List<NetworkObject> rootChildren,
    NetworkObject root,
    bool isPersistent)
  {
    NetworkObject component1 = obj.GetComponent<NetworkObject>();
    if (rootChildren != null && (Object) component1 != (Object) null && (component1.gameObject.activeInHierarchy || this.Sandbox.Config.IncludeInactiveObjects))
    {
      component1._IsPersistent = isPersistent;
      component1.PrefabId = prefabId;
      component1._SceneId = -1;
      component1.PrefabRoot = root;
      component1.PrefabIndex = rootChildren.Count;
      component1.Children = new NetworkObject[0];
      rootChildren.Add(component1);
    }
    foreach (Component component2 in obj.transform)
      this.ConfigurePrefabChild(component2.gameObject, prefabId, rootChildren, root, isPersistent);
  }

  public void Push(GameObject obj)
  {
    obj.SetActive(false);
    obj.hideFlags = this.HideUnspawned ? HideFlags.HideInHierarchy : HideFlags.None;
    this.Free.Push(obj);
  }
}
